import { isInterval, isMyRoom, isOfficialShard } from '@/ayaka'
import { RemoteHarvestTask, RemoteSourceInfo } from './types'
import SpawnController, { getCreeps } from '@/modules/structures/spawn'
import { CONTROLLER_ENERGY } from '@/utils/constants'
import { CreepRoles } from '@/modules/structures/spawn/types'
import { BodyPartArrayType, getCreepWorking } from '@/utils/common'
import { goTo } from '@/modules/move'

/**
 * 孵化远程采集者
 */
export const spawnRemoteHarvester = function (room: MyRoom, task: RemoteHarvestTask) {
    if (!isInterval(11)) return

    if (SpawnController.searchSpawnTaskByRole(room, CreepRoles.remoteHarvester).length) return

    for (const sourceInfo of Object.values(task.data.source)) {
        if (sourceInfo.remoteHarvester.length >= 2) continue
        if (sourceInfo.remoteHarvester.length) {
            const creep = Game.creeps[sourceInfo.remoteHarvester[0]]
            if (!creep || !creep.ticksToLive || creep.ticksToLive > sourceInfo.roadLength * 2 + 30) continue
        }

        // 挖元素矿必须有 container 且元素矿已生成
        if (sourceInfo.type !== 'energy' && (!sourceInfo.containerId || sourceInfo.timeToRegeneration! > Game.time))
            continue

        const creepName = SpawnController.addSpawnTask(room, {
            role: CreepRoles.remoteHarvester,
            body: getRemoteHarvesterBody(room, task, sourceInfo),
            defaultAdaption: true,
        })
        if (creepName) {
            sourceInfo.remoteHarvester.push(creepName)
        }
        return
    }
}

/**
 * 生成远程采集者身体部件
 */
const getRemoteHarvesterBody = function (
    room: Room,
    task: RemoteHarvestTask,
    sourceInfo: RemoteSourceInfo,
): BodyPartArrayType {
    // 挖元素矿要大体型
    if (task.isCenterNine) {
        if (sourceInfo.type !== 'energy') {
            return [
                [WORK, 40],
                [MOVE, 10],
            ]
        } else {
            return [
                [WORK, 10],
                [CARRY, 2],
                [MOVE, 5],
            ]
        }
    }

    const energyCapacityAvailable = room.energyCapacityAvailable
    let body: BodyPartArrayType
    if (energyCapacityAvailable <= CONTROLLER_ENERGY[1]) {
        body = [
            [WORK, 2],
            [CARRY, 1],
            [MOVE, 1],
        ]
    } else if (energyCapacityAvailable <= CONTROLLER_ENERGY[2]) {
        body = [
            [WORK, 3],
            [CARRY, 1],
            [MOVE, 1],
        ]
    } else if (energyCapacityAvailable <= CONTROLLER_ENERGY[4]) {
        body = [
            [WORK, 6],
            [CARRY, 1],
            [MOVE, 2],
        ]
    } else if (energyCapacityAvailable <= CONTROLLER_ENERGY[5]) {
        body = [
            [WORK, 8],
            [CARRY, 1],
            [MOVE, 2],
        ]
    } else {
        body = [
            [WORK, 12],
            [CARRY, 1],
            [MOVE, 3],
        ]
    }

    // 私服搞小点
    if (
        !isOfficialShard() &&
        energyCapacityAvailable > CONTROLLER_ENERGY[4] &&
        energyCapacityAvailable <= CONTROLLER_ENERGY[7]
    ) {
        body = [
            [WORK, 6],
            [CARRY, 1],
            [MOVE, 2],
        ]
    }

    return body
}

/**
 * 远程采集者工作
 */
export const remoteHarvesterWork = function (room: MyRoom, task: RemoteHarvestTask, remoteRoom?: Room) {
    const isNormalCenterNine = task.isCenterNine && !task.isCenter

    Object.keys(task.data.source).forEach((sourceId: Id<Source | Mineral>) => {
        const sourceInfo = task.data.source[sourceId]
        const creeps = getCreeps(room, sourceInfo.remoteHarvester).filter((creep) => !creep.spawning)

        if (isInterval(131) && task.isCenterNine && sourceInfo.type !== 'energy' && remoteRoom && !creeps.length) {
            // 九房元素矿不要等矿工来了再放 container，提前放！
            if (sourceInfo.containerId) {
                const container = Game.getObjectById(sourceInfo.containerId)
                if (!container) {
                    delete sourceInfo.containerId
                }
            }

            const source = Game.getObjectById(sourceId)!
            if (!sourceInfo.containerId) {
                const container = source.pos.findInRange(FIND_STRUCTURES, 1, {
                    filter: { structureType: STRUCTURE_CONTAINER },
                })[0] as StructureContainer | undefined
                if (container) {
                    sourceInfo.containerId = container.id
                    return
                }

                const containerSite = source.pos.findInRange(FIND_CONSTRUCTION_SITES, 1, {
                    filter: { structureType: STRUCTURE_CONTAINER },
                })[0]
                if (!containerSite) {
                    const roads = sourceInfo.roads[remoteRoom.name]
                    const [x, y] = roads[roads.length - 1].split('/').map(Number)
                    const existSite = remoteRoom.lookForAt(LOOK_CONSTRUCTION_SITES, x, y)[0]
                    if (existSite) {
                        if (existSite.my) {
                            existSite.remove()
                        } else {
                            // TODO：其他人的工地踩掉
                        }
                    }
                    remoteRoom.createConstructionSite(x, y, STRUCTURE_CONTAINER)
                    return
                }
            }
        }

        creeps.forEach((creep) => {
            if (!creep.memory.data) {
                creep.memory.data = {
                    rooms: [],
                } as RemoteHarvesterData
            }
            delete creep.memory.stand
            const data = creep.memory.data as RemoteHarvesterData
            const currentRoom = creep.room

            if (!data.rooms.includes(currentRoom.name)) {
                const roads = sourceInfo.roads[currentRoom.name] || []
                if (roads.length) {
                    // 已经放置的道路数量，每次只放 10 个
                    let placed = 0
                    if (isMyRoom(currentRoom)) {
                        // 自己的房间读缓存
                        const existRoads = new Set(Object.values(currentRoom.memory.structures.road || {}))
                        roads.forEach((road) => {
                            if (placed >= 10) return
                            if (existRoads.has(road)) return
                            const [x, y] = road.split('/').map(Number)
                            currentRoom.createConstructionSite(x, y, STRUCTURE_ROAD)
                            placed++
                        })
                    } else if (roads.length >= 2) {
                        // 其他房间直接建造，最后一个位置不放
                        // TODO: 优化外矿道路创建
                        for (let index = roads.length - 2; index >= 0; index--) {
                            const road = roads[index]
                            if (placed >= 10) continue
                            const [x, y] = road.split('/').map(Number)
                            const result = currentRoom.createConstructionSite(x, y, STRUCTURE_ROAD)
                            if (result === OK) placed++
                            else if (result === ERR_FULL) break
                        }
                    }
                }
                data.rooms.push(currentRoom.name)
            }

            if (!data.isDanger && creep.hits < creep.hitsMax) {
                data.isDanger = true
                task.data.isDanger = true
            }

            if (!remoteRoom) {
                goTo(creep, new RoomPosition(25, 25, task.roomName), { range: 23 })
                return
            }

            const source = Game.getObjectById(sourceId)!
            let container: StructureContainer | null = null
            let containerSite: ConstructionSite | null = null

            if (sourceInfo.containerId) {
                container = Game.getObjectById(sourceInfo.containerId)
                if (!container) {
                    delete sourceInfo.containerId
                    return
                }
            } else {
                if (!creep.memory.ready) {
                    creep.memory.ready = true
                    const container = source.pos.findInRange(FIND_STRUCTURES, 1, {
                        filter: { structureType: STRUCTURE_CONTAINER },
                    })[0] as StructureContainer | undefined
                    if (container) {
                        sourceInfo.containerId = container.id
                        return
                    }
                }
                if (!data.containerSiteId) {
                    const containerSite = source.pos.findInRange(FIND_CONSTRUCTION_SITES, 1, {
                        filter: { structureType: STRUCTURE_CONTAINER },
                    })[0]
                    if (containerSite) {
                        data.containerSiteId = containerSite.id
                    } else {
                        const roads = sourceInfo.roads[remoteRoom.name]
                        const [x, y] = roads[roads.length - 1].split('/').map(Number)
                        const existSite = remoteRoom.lookForAt(LOOK_CONSTRUCTION_SITES, x, y)[0]
                        if (existSite) {
                            if (existSite.my) {
                                existSite.remove()
                            } else {
                                // TODO：其他人的工地踩掉
                            }
                        }
                        remoteRoom.createConstructionSite(x, y, STRUCTURE_CONTAINER)
                        return
                    }
                }
            }

            if (data.containerSiteId) {
                containerSite = Game.getObjectById(data.containerSiteId)
                if (!containerSite) {
                    delete data.containerSiteId
                    delete creep.memory.ready
                }
            }

            getCreepWorking(creep)
            if (creep.memory.slack) return

            // 中央九房特殊处理
            if (isNormalCenterNine && remoteRoom?.name === creep.room.name) {
                if (!data.keeperLairId) {
                    const keeperLair = source.pos.findInRange(FIND_STRUCTURES, 5, {
                        filter: { structureType: STRUCTURE_KEEPER_LAIR },
                    })[0] as StructureKeeperLair | undefined
                    if (keeperLair) {
                        data.keeperLairId = keeperLair.id
                    }
                }

                if (remoteRoom.enemys?.length) {
                    // 离最近的敌人5格远
                    const enemy = creep.pos.findClosestByRange(remoteRoom.enemys)
                    if (enemy) {
                        const range = creep.pos.getRangeTo(enemy)
                        if (range < 5) {
                            goTo(creep, enemy.pos, { range: 5, flee: true })
                            return
                        } else if (range === 5) return
                    }
                }

                if (data.keeperLairId) {
                    const keeperLair = Game.getObjectById(data.keeperLairId)
                    if (keeperLair) {
                        // 提前跑
                        if (keeperLair.ticksToSpawn! < 12 && creep.pos.getRangeTo(keeperLair) < 6) {
                            goTo(creep, keeperLair.pos, { range: 6, flee: true })
                            return
                        }
                    } else {
                        delete data.keeperLairId
                    }
                }
            }

            if (creep.memory.working) {
                if (container) {
                    if (!creep.pos.isEqualTo(container)) {
                        goTo(creep, container.pos, { range: 0 })
                    } else if (container.hits < 240000) {
                        creep.repair(container)
                    } else if (container.store.getFreeCapacity('energy') > 30) {
                        creep.memory.stand = true
                        const result = creep.harvest(source)
                        if (result === ERR_NOT_ENOUGH_RESOURCES) {
                            creep.memory.slack = source.ticksToRegeneration
                        } else if (result === ERR_NOT_OWNER) {
                            creep.memory.slack = 20
                            task.data.isDanger = true
                        }
                    }
                } else if (containerSite) {
                    if (creep.pos.getRangeTo(containerSite) > 3) {
                        goTo(creep, containerSite.pos, { range: 3 })
                    } else {
                        creep.build(containerSite)
                    }
                }
            } else {
                if (container && !creep.pos.isEqualTo(container)) {
                    goTo(creep, container.pos, { range: 0 })
                } else if (!creep.pos.isNearTo(source)) {
                    if (creep.room.name === remoteRoom.name) {
                        goTo(creep, source.pos, { maxRooms: 1 })
                    } else {
                        goTo(creep, source.pos)
                    }
                } else {
                    const result = creep.harvest(source)
                    if (result === ERR_NOT_ENOUGH_RESOURCES) {
                        creep.memory.slack = source.ticksToRegeneration
                        if (sourceInfo.type !== 'energy') {
                            sourceInfo.timeToRegeneration = Game.time + (source.ticksToRegeneration || 0)
                        }
                    } else if (result === ERR_NOT_OWNER) {
                        creep.memory.slack = 20
                        task.data.isDanger = true
                    }
                }
            }
        })
    })
}

interface RemoteHarvesterData {
    /**
     * 经过的房间
     */
    rooms: string[]
    /**
     * 是否设置过危险标志
     */
    isDanger?: boolean
    /**
     * container 建筑工地id
     */
    containerSiteId?: Id<ConstructionSite>
    /**
     * keeperlair 的id
     */
    keeperLairId?: Id<StructureKeeperLair>
}
